import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * A simple model of a rabbit.
 * Rabbits age, move, breed, and die.
 * 
 * @author David J. Barnes and Michael Kolling
 * @version 2008.03.30
 */
public class Rabbit extends Animal
{
    // Characteristics shared by all rabbits (static fields).

    // The age at which a rabbit can start to breed.
    private static final int BREEDING_AGE = 5;
    // The age to which a rabbit can live.
    private static final int MAX_AGE = 40;
    // The likelihood of a rabbit breeding.
    private static final double BREEDING_PROBABILITY = 0.15;
    // The maximum number of births.
    private static final int MAX_LITTER_SIZE = 4;
    // A shared random number generator to control breeding.
    private int foodValue;
    
    private static final int MAX_FOOD_VALUE = 10;
    
    private static final Random rand = Randomizer.getRandom();
    
    // Individual characteristics (instance fields).
    
    // The rabbit's age.
    private int age;

    /**
     * Create a new rabbit. A rabbit may be created with age
     * zero (a new born) or with a random age.
     * 
     * @param randomAge If true, the rabbit will have a random age.
     * @param field The field currently occupied.
     * @param location The location within the field.
     */
    public Rabbit(boolean randomAge, Field field, Location location)
    {
        super(field, location);
        age = 0;
        foodValue = new Random().nextInt(MAX_FOOD_VALUE);
        if(randomAge) {
            age = new Random().nextInt(MAX_AGE);
        }
    }
    
    /**
     * This is what the rabbit does most of the time - it runs 
     * around. Sometimes it will breed or die of old age.
     * @param newRabbits A list to add newly born rabbits to.
     */
    public void act(List<Actor> newRabbits)
    {
        incrementAge();
        if (isActive()) {
        	if (FieldStats.getAnimalAmount(Grass.class) > 0) {
        		giveBirth(newRabbits);
        	}
            foodValue--;
            if(foodValue < 0){
            	setDead();
            }else{
	            getGrassLocationAndEat();
	            // Try to move into a free location.
	            Location newLocation = getField().freeAdjacentLocation(getLocation());
	            if(newLocation != null) {
	                setLocation(newLocation);
	            }
	            else {
	                // Overcrowding.
	                setDead();
	            }
            }
        }
    }

    /**
     * Increase the age.
     * This could result in the rabbit's death.
     */
    private void incrementAge()
    {
        age++;
        if(age > MAX_AGE) {
            setDead();
        }
    }
    
    /**
     * Check whether or not this rabbit is to give birth at this step.
     * New births will be made into free adjacent locations.
     * @param newRabbits A list to add newly born rabbits to.
     */
    private void giveBirth(List<Actor> newRabbits)
    {
        // New rabbits are born into adjacent locations.
        // Get a list of adjacent free locations.
        Field field = getField();
        List<Location> free = field.getFreeAdjacentLocations(getLocation());
        int births = breed();
        for(int b = 0; b < births && free.size() > 0; b++) {
            Location loc = free.remove(0);
            Rabbit young = new Rabbit(false, field, loc);
            newRabbits.add(young);
        }
    }
    
    
    public List<Location> getGrassLocationAndEat() {
    	// Get a list of adjacent free locations.
        Field field = getField();
        List<Location> free = field.adjacentLocations(getLocation());
        List<Location> locations = new LinkedList<Location>();
        for (int x = 0; x < free.size() - 1; x++) {
        	if (field.getObjectAt(free.get(x)) instanceof Grass && MAX_FOOD_VALUE>foodValue) {
        		foodValue+=10;
        		locations.add(free.get(x));
        		Grass g = (Grass) field.getObjectAt(free.get(x));
        		g.lowerGrassAmount(free.get(x));
        		
        	}
        }
        return locations;
    }
    
    public int getGrassCount() { 
    	Field field = getField();
        List<Location> free = field.adjacentLocations(getLocation());
        int counter = 0;
        for (int x = 0; x < free.size() - 1; x++) {
        	if (field.getObjectAt(free.get(x)) instanceof Grass) {
        		counter++;
        	}
        
        }
        return counter;
    }
        
    /**
     * Generate a number representing the number of births,
     * if it can breed.
     * @return The number of births (may be zero).
     */
    private int breed()
    {
        int births = 0;
        if(canBreed() && rand.nextDouble() <= BREEDING_PROBABILITY) {
            births = rand.nextInt(MAX_LITTER_SIZE) + 1;
        }
        return births;
    }

    /**
     * A rabbit can breed if it has reached the breeding age.
     * @return true if the rabbit can breed, false otherwise.
     */
    private boolean canBreed()
    {
        return age >= BREEDING_AGE && foodValue>1;
    }
    
}

